feat: support local Ollama for embeddings and fact-extraction LLM - #79
Merged
Conversation
Adds opt-in config for running mem0's embedder and/or LLM against a local Ollama server — zero per-call cost and no content leaving the host — while keeping anthropic+openai as the default. - config.py: new OLLAMA_BASE_URL setting (default http://localhost:11434). The existing provider-key validator already skips key checks for non anthropic/openai providers, so ollama needs no API key. - memory.py: _provider_config() is now provider-aware — cloud providers get the API key injected; an "ollama" provider gets mem0's ollama_base_url (and embedding_dims for the embedder) and no key. Wired through _build_config for both llm and embedder, so fully-local and mixed cloud/local setups work. - .env.example / docker-compose.yml: documented vars plus a commented-out optional bundled `ollama` service for the Compose stack. - USER_GUIDE: "Running fully local with Ollama" section + config-table rows, prominently restating the MEM0_EMBED_DIMS-must-match invariant (recreate the Qdrant collection when switching embed models). DEVELOPER_GUIDE: updated the _provider_config internals note. - Tests: ollama config building (fully-local + mixed), OLLAMA_BASE_URL default/override, and Ollama config validated against the real mem0 MemoryConfig schema so a key rename is caught in CI. Closes #51. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XQXUARh5h5hRFg67toenEX
There was a problem hiding this comment.
Pull request overview
Adds opt-in support for running mem0’s embedder and/or fact-extraction LLM against a local Ollama server, while preserving the existing Anthropic (LLM) + OpenAI (embedder) defaults. This is primarily provider-config wiring plus documentation and tests to ensure the generated mem0 config matches the pinned mem0 schema.
Changes:
- Add
OLLAMA_BASE_URLsetting and wireollama_base_url(+embedding_dimsfor embeddings) into mem0 provider config. - Expand docs and
.env.exampleto document fully-local and mixed cloud/local setups, plus a commented optionalollamaDocker Compose service. - Add tests for Ollama config shapes and schema validation against
mem0.configs.base.MemoryConfig.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
app/config.py |
Adds ollama_base_url setting (default http://localhost:11434). |
app/memory.py |
Makes provider config provider-aware and wires Ollama base URL + embedding dims into mem0 config. |
tests/test_memory.py |
Adds tests for Ollama-only and mixed provider config shapes + validates against real mem0 schema. |
tests/test_config.py |
Adds test coverage for OLLAMA_BASE_URL default/override. |
docs/USER_GUIDE.md |
Documents Ollama usage, config reference updates, and the embed-dims/Qdrant invariant. |
docs/DEVELOPER_GUIDE.md |
Updates internal notes about _provider_config() behavior for cloud vs Ollama. |
docker-compose.yml |
Adds a commented-out optional ollama service and volume notes. |
.env.example |
Documents Ollama-related env vars and a fully-local example block. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Addresses PR review: _build_config previously hardcoded the Anthropic key into the LLM config and the OpenAI key into the embedder config regardless of the configured provider. With openai now documented as a valid MEM0_LLM_PROVIDER, an OpenAI LLM would have received the Anthropic key (and no OpenAI key), silently failing at first request. - memory.py: add _api_key_for(provider) so each provider gets its own key (anthropic->ANTHROPIC_API_KEY, openai->OPENAI_API_KEY, ollama/other->none). - config.py: _require_provider_keys now requires a provider's key when *either* role selects it, so openai-LLM + ollama-embed no longer passes validation without OPENAI_API_KEY. - Tests: openai-LLM key routing, and validation raises for a missing key when openai/anthropic is the LLM (or embed) provider. - Docs: config-table key requirements and the DEVELOPER_GUIDE validator note updated to reflect either-role enforcement. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XQXUARh5h5hRFg67toenEX
Addresses PR review follow-ups: - config.py: reword the _require_provider_keys comment — mem0's clients DO read keys from os.environ; the reason we inject is that a key loaded from .env via pydantic-settings never lands in os.environ. The old wording said the opposite and contradicted the note in app/memory.py. - tests: remove test_missing_anthropic_key_rejected_for_embed_provider. It implied Anthropic is a valid embed provider, but Anthropic has no embeddings API and the docs list only openai/ollama for embedding — the real key-backed cases (anthropic LLM, openai LLM or embed) stay covered. Also drop the same misleading os.environ phrasing from the openai-LLM test comment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XQXUARh5h5hRFg67toenEX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #51.
What
Adds first-class, opt-in config for running mem0's embedder and/or fact-extraction LLM against a local Ollama server — zero per-call cost and no content leaving the host — while keeping
anthropic+openaias the default. As the issue notes,_build_configalready abstracts the providers, so this is a config + wiring + docs change, not a re-architecture. No change to the single-Memory-per-process invariant.Changes
app/config.py— newOLLAMA_BASE_URLsetting (defaulthttp://localhost:11434). The existing_require_provider_keysvalidator already enforces a provider's key only when that provider is selected, soollamaneeds noANTHROPIC_API_KEY/OPENAI_API_KEY.app/memory.py—_provider_config()is now provider-aware: cloud providers get the API key injected explicitly (as before), while anollamaprovider gets mem0'sollama_base_urlkey (andembedding_dimsfor the embedder) and no key. Wired through_build_config()for bothllmandembedder, so fully-local and mixed cloud/local setups both work..env.example— documentedOLLAMA_BASE_URL+ a commented-out fully-local provider block.docker-compose.yml— commented-out optional bundledollamaservice (+ollama_datavolume) for the self-contained stack, with model-pull notes and an optional GPU block.docs/USER_GUIDE.md— new "Running fully local with Ollama" section and config-table rows, prominently restating the criticalMEM0_EMBED_DIMS-must-match invariant (switching embed models — including cloud↔local — means dropping/recreating the Qdrant collection).docs/DEVELOPER_GUIDE.md— updated the_provider_configinternals note.Config keys (verified against mem0 2.0.2)
{"llm": {"provider": "ollama", "config": {"model": "llama3.1:8b", "ollama_base_url": "http://localhost:11434"}}, "embedder": {"provider": "ollama", "config": {"model": "nomic-embed-text", "ollama_base_url": "http://localhost:11434", "embedding_dims": 768}}}Verification
ruff checkclean; 241 tests pass (pytest -q) against the pinnedmem0ai==2.0.2.OLLAMA_BASE_URLdefault/override, and — critically — the Ollama config is validated against the realmem0.configs.base.MemoryConfigschema, so a future mem0 rename ofollama_base_urlis caught in CI rather than at deploy time.test_build_config_shapestill passes untouched).🤖 Generated with Claude Code
Generated by Claude Code